/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.seguradora.model.repository.impl;

import br.com.seguradora.exception.PersistenciaException;
import br.com.seguradora.model.Associado;
import br.com.seguradora.model.Endereco;
import br.com.seguradora.model.Telefone;
import br.com.seguradora.model.constant.EstadoCivil;
import br.com.seguradora.model.constant.TipoTelefone;
import br.com.seguradora.model.constant.UnidadeFederativa;
import br.com.seguradora.model.repository.TodosAssociados;
import br.com.seguradora.persistence.GerenciadorDeConexao;
import br.com.seguradora.view.DisplayFilter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 *
 * @author Diego
 */
public class TodosAssociadosImpl implements TodosAssociados {
    
    private Connection conn;
    private PreparedStatement pr;
    private ResultSet rs;
    
    @Override
    public boolean inserir(Associado associado) throws PersistenciaException {
        if (associado == null) {
            throw new PersistenciaException("Não foi informado o associado a cadastrar.");
        }
        boolean sucesso = false;
        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("INSERT INTO ASSOCIADO(ID, BLOQUEADO, NOME, CPF, RG, ORG_EXP, DATA_NASCIMENTO, ESTADO_CIVIL, DATA_CADASTRO, OBSERVACAO, ID_ENDERECO, COMPLEMENTO, SHADOW) VALUES(NULL, TRUE, ?, ?, ?, ?, ?, ?, CURDATE(), ?, ?, ?, FALSE);",
                    Statement.RETURN_GENERATED_KEYS);
            pr.setString(1, associado.getNome());
            pr.setString(2, associado.getCpf());
            pr.setString(3, associado.getRg());
            pr.setString(4, associado.getOrgExp());
            pr.setDate(5, new java.sql.Date(associado.getDataNascimento().getTime()));
            pr.setString(6, associado.getEstadoCivil().name());
            pr.setString(7, associado.getObservacao());
            pr.setLong(8, associado.getEndereco() != null ? associado.getEndereco().getId() : 0);
            pr.setString(9, associado.getEndereco() != null ? associado.getEndereco().getComplemento() : null);
            int linhas = pr.executeUpdate();
            if (linhas > 0) {
                sucesso = true;
                rs = pr.getGeneratedKeys();
                rs.first();
                long id = rs.getLong(1);
                associado.setId(id);
                
                inserirTelefones(associado);
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível cadastrar o associado.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }
        return sucesso;
    }
    
    @Override
    public boolean atualizar(Associado associado) throws PersistenciaException {
        if (associado == null) {
            throw new PersistenciaException("Não foi informado o associado a atualizar.");
        }
        boolean sucesso = false;
        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("UPDATE ASSOCIADO SET BLOQUEADO=?, NOME=?, CPF=?, RG=?, ORG_EXP=?, DATA_NASCIMENTO=?, ESTADO_CIVIL=?, OBSERVACAO=?, ID_ENDERECO=?, COMPLEMENTO=? WHERE ID=?;");
            pr.setBoolean(1, associado.isBloqueado());
            pr.setString(2, associado.getNome());
            pr.setString(3, associado.getCpf());
            pr.setString(4, associado.getRg());
            pr.setString(5, associado.getOrgExp());
            pr.setDate(6, new java.sql.Date(associado.getDataNascimento().getTime()));
            pr.setString(7, associado.getEstadoCivil().name());
            pr.setString(8, associado.getObservacao());
            pr.setLong(9, associado.getEndereco() != null ? associado.getEndereco().getId() : null);
            pr.setString(10, associado.getEndereco() != null ? associado.getEndereco().getComplemento() : null);
            pr.setLong(11, associado.getId());
            int linhas = pr.executeUpdate();
            if (linhas > 0) {
                inserirTelefones(associado);
                sucesso = true;
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível atualizar o associado.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr);
        }
        return sucesso;
    }
    
    @Override
    public boolean excluir(Associado associado) throws PersistenciaException {
        if (associado == null) {
            throw new PersistenciaException("Não foi informado o associado a excluir.");
        }
        boolean sucesso = false;
        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("UPDATE ASSOCIADO SET SHADOW=TRUE WHERE ID=?;");
            pr.setLong(1, associado.getId());
            int linhas = pr.executeUpdate();
            if (linhas > 0) {
                sucesso = true;
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível excluir o associado.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr);
        }
        return sucesso;
    }
    
    @Override
    public List<Associado> listarTodos(int... limits) throws PersistenciaException {
        List<Associado> lista = new ArrayList<Associado>();
        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("SELECT A.ID, A.BLOQUEADO, A.NOME, A.CPF, A.RG, A.ORG_EXP, A.DATA_NASCIMENTO, A.ESTADO_CIVIL, A.DATA_CADASTRO, A.OBSERVACAO, A.ID_ENDERECO, A.COMPLEMENTO, E.CEP, E.LOGRADOURO, E.BAIRRO, E.CIDADE, E.ESTADO FROM ASSOCIADO A LEFT JOIN ENDERECO E ON A.ID_ENDERECO = E.ID WHERE A.SHADOW=FALSE ORDER BY A.ID DESC LIMIT ?, ?");
            pr.setInt(1, limits[0]);
            pr.setInt(2, limits[1]);
            rs = pr.executeQuery();
            while (rs.next()) {
                Associado associado = this.criarAssociado(rs);
                lista.add(associado);
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível listar os associados.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }
        return lista;
    }
    
    @Override
    public List<Associado> listarPeloNome(String nome, DisplayFilter displayFilter) throws PersistenciaException {
        List<Associado> lista = new ArrayList<Associado>();
        try {
            conn = GerenciadorDeConexao.abreConexao();
            if (displayFilter != DisplayFilter.TODOS) {
                pr = conn.prepareStatement("SELECT A.ID, A.BLOQUEADO, A.NOME, A.CPF, A.RG, A.ORG_EXP, A.DATA_NASCIMENTO, A.ESTADO_CIVIL, A.DATA_CADASTRO, A.OBSERVACAO, A.ID_ENDERECO, A.COMPLEMENTO, E.CEP, E.LOGRADOURO, E.BAIRRO, E.CIDADE, E.ESTADO FROM ASSOCIADO A LEFT JOIN ENDERECO E ON A.ID_ENDERECO = E.ID WHERE A.SHADOW=FALSE AND A.NOME LIKE ? AND A.BLOQUEADO=? ORDER BY A.NOME");
                pr.setBoolean(2, displayFilter.getValue());
            } else {
                pr = conn.prepareStatement("SELECT A.ID, A.BLOQUEADO, A.NOME, A.CPF, A.RG, A.ORG_EXP, A.DATA_NASCIMENTO, A.ESTADO_CIVIL, A.DATA_CADASTRO, A.OBSERVACAO, A.ID_ENDERECO, A.COMPLEMENTO, E.CEP, E.LOGRADOURO, E.BAIRRO, E.CIDADE, E.ESTADO FROM ASSOCIADO A LEFT JOIN ENDERECO E ON A.ID_ENDERECO = E.ID WHERE A.SHADOW=FALSE AND A.NOME LIKE ? ORDER BY A.NOME");
            }
            pr.setString(1, "%" + nome + "%");
            rs = pr.executeQuery();
            while (rs.next()) {
                Associado associado = this.criarAssociado(rs);
                lista.add(associado);
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível listar os associados pelo nome.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }
        return lista;
    }
    
    @Override
    public List<Associado> listarPeloCpf(String cpf, DisplayFilter displayFilter) throws PersistenciaException {
        List<Associado> lista = new ArrayList<Associado>();
        try {
            conn = GerenciadorDeConexao.abreConexao();
            if (displayFilter != DisplayFilter.TODOS) {
                pr = conn.prepareStatement("SELECT A.ID, A.BLOQUEADO, A.NOME, A.CPF, A.RG, A.ORG_EXP, A.DATA_NASCIMENTO, A.ESTADO_CIVIL, A.DATA_CADASTRO, A.OBSERVACAO, A.ID_ENDERECO, A.COMPLEMENTO, E.CEP, E.LOGRADOURO, E.BAIRRO, E.CIDADE, E.ESTADO FROM ASSOCIADO A LEFT JOIN ENDERECO E ON A.ID_ENDERECO = E.ID WHERE A.SHADOW=FALSE AND A.CPF=? AND A.BLOQUEADO=? ORDER BY A.NOME");
                pr.setBoolean(2, displayFilter.getValue());
            } else {
                pr = conn.prepareStatement("SELECT A.ID, A.BLOQUEADO, A.NOME, A.CPF, A.RG, A.ORG_EXP, A.DATA_NASCIMENTO, A.ESTADO_CIVIL, A.DATA_CADASTRO, A.OBSERVACAO, A.ID_ENDERECO, A.COMPLEMENTO, E.CEP, E.LOGRADOURO, E.BAIRRO, E.CIDADE, E.ESTADO FROM ASSOCIADO A LEFT JOIN ENDERECO E ON A.ID_ENDERECO = E.ID WHERE A.SHADOW=FALSE AND A.CPF=? ORDER BY A.NOME");
            }
            pr.setString(1, cpf);
            rs = pr.executeQuery();
            while (rs.next()) {
                Associado associado = this.criarAssociado(rs);
                lista.add(associado);
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível listar os associados pelo cpf.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }
        return lista;
    }
    
    private void inserirTelefones(Associado associado) throws PersistenciaException {
        try {
            pr = conn.prepareStatement("DELETE FROM TELEFONE_ASSOCIADO WHERE ID_ASSOCIADO=?;");
            pr.setLong(1, associado.getId());
            pr.executeUpdate();
            
            pr = conn.prepareStatement("INSERT INTO TELEFONE_ASSOCIADO(ID, TIPO, DDD, NUMERO, RAMAL, ID_ASSOCIADO) VALUES(NULL, ?, ?, ?, ?, ?);");
            List<Telefone> telefonesList = associado.getTelefonesList();
            for (Telefone telefone : telefonesList) {
                pr.setString(1, telefone.getTipo().name());
                pr.setString(2, telefone.getDdd());
                pr.setString(3, telefone.getNumero());
                pr.setString(4, telefone.getRamal());
                pr.setLong(5, associado.getId());
                pr.executeUpdate();
                pr.clearParameters();
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível inserir os telefones do associado.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        }
    }
    
    @Override
    public void getTelefones(Associado associado) throws PersistenciaException {
        try {
            associado.setTelefonesList(new ArrayList<Telefone>());
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("SELECT T.ID, T.TIPO, T.DDD, T.NUMERO, T.RAMAL FROM TELEFONE_ASSOCIADO T INNER JOIN ASSOCIADO A ON T.ID_ASSOCIADO=? AND T.ID_ASSOCIADO = A.ID ORDER BY T.ID;");
            pr.setLong(1, associado.getId());
            rs = pr.executeQuery();
            while (rs.next()) {
                Telefone telefone = new Telefone(rs.getLong("ID"));
                telefone.setTipo(TipoTelefone.valueOf(rs.getString("TIPO")));
                telefone.setDdd(rs.getString("DDD"));
                telefone.setNumero(rs.getString("NUMERO"));
                telefone.setRamal(rs.getString("RAMAL"));
                
                associado.getTelefonesList().add(telefone);
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível listar os telefones do associado.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        }  finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }
    }
    
    private Associado criarAssociado(ResultSet rs) throws PersistenciaException {
        Associado associado = null;
        try {
            associado = new Associado(rs.getLong("ID"));
            associado.setBloqueado(rs.getBoolean("BLOQUEADO"));
            associado.setNome(rs.getString("NOME"));
            associado.setCpf(rs.getString("CPF"));
            associado.setRg(rs.getString("RG"));
            associado.setOrgExp(rs.getString("ORG_EXP"));
            associado.setDataNascimento(new Date(rs.getDate("DATA_NASCIMENTO").getTime()));
            associado.setEstadoCivil(EstadoCivil.valueOf(rs.getString("ESTADO_CIVIL")));
            associado.setDataCadastro(new Date(rs.getDate("DATA_CADASTRO").getTime()));
            associado.setObservacao(rs.getString("OBSERVACAO"));
            
            long id = rs.getLong("ID_ENDERECO");
            if (id > 0) {
                Endereco endereco = new Endereco(id);
                endereco.setCep(rs.getString("CEP"));
                endereco.setLogradouro(rs.getString("LOGRADOURO"));
                endereco.setBairro(rs.getString("BAIRRO"));
                endereco.setCidade(rs.getString("CIDADE"));
                endereco.setUf(UnidadeFederativa.valueOf(rs.getString("ESTADO")));
                endereco.setComplemento(rs.getString("COMPLEMENTO"));
                associado.setEndereco(endereco);
            }
        } catch (SQLException sqlex) {
            StringBuilder msg = new StringBuilder("Não foi possível obter os dados do associado.");
            msg.append("\nMotivo: ").append(sqlex.getMessage());
            throw new PersistenciaException(msg.toString());
        }
        return associado;
    }
    
    @Override
    public List<Associado> listarPeloCep(String cep, DisplayFilter displayFilter) throws PersistenciaException {
        List<Associado> lista = new ArrayList<Associado>();
        try {
            conn = GerenciadorDeConexao.abreConexao();
            if (displayFilter != DisplayFilter.TODOS) {
                pr = conn.prepareStatement("SELECT A.ID, A.BLOQUEADO, A.NOME, A.CPF, A.RG, A.ORG_EXP, A.DATA_NASCIMENTO, A.ESTADO_CIVIL, A.DATA_CADASTRO, A.OBSERVACAO, A.ID_ENDERECO, A.COMPLEMENTO, E.CEP, E.LOGRADOURO, E.BAIRRO, E.CIDADE, E.ESTADO FROM ASSOCIADO A INNER JOIN ENDERECO E ON A.ID_ENDERECO = E.ID WHERE A.SHADOW=FALSE AND E.CEP=? AND A.BLOQUEADO=? ORDER BY A.NOME");
                pr.setBoolean(2, displayFilter.getValue());
            } else {
                pr = conn.prepareStatement("SELECT A.ID, A.BLOQUEADO, A.NOME, A.CPF, A.RG, A.ORG_EXP, A.DATA_NASCIMENTO, A.ESTADO_CIVIL, A.DATA_CADASTRO, A.OBSERVACAO, A.ID_ENDERECO, A.COMPLEMENTO, E.CEP, E.LOGRADOURO, E.BAIRRO, E.CIDADE, E.ESTADO FROM ASSOCIADO A INNER JOIN ENDERECO E ON A.ID_ENDERECO = E.ID WHERE A.SHADOW=FALSE AND E.CEP=? ORDER BY A.NOME");
            }
            pr.setString(1, cep);
            rs = pr.executeQuery();
            while (rs.next()) {
                Associado associado = this.criarAssociado(rs);
                lista.add(associado);
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível listar os associados pelo cep.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }
        return lista;
    }
}
